/**
 * Copyright (C) 2018-2021
 * All rights reserved, Designed By www.yixiang.co
 */
package co.yixiang.modules.security.security;

import cn.hutool.core.util.ObjectUtil;
import co.yixiang.cache.Cache;
import co.yixiang.cache.CachePrefix;
import co.yixiang.common.enums.ResultCode;
import co.yixiang.common.exception.ServiceException;
import co.yixiang.common.utils.ResponseUtil;
import co.yixiang.common.utils.SpringContextHolder;
import co.yixiang.common.utils.StringUtils;
import co.yixiang.modules.security.config.SecurityProperties;
import co.yixiang.modules.security.entity.vo.AuthUser;
import co.yixiang.modules.security.entity.vo.JwtUser;
import co.yixiang.modules.security.entity.vo.OnlineUser;
import co.yixiang.modules.security.enums.UserEnums;
import co.yixiang.modules.security.security.TokenUtil;
import co.yixiang.modules.security.service.OnlineUserService;
import com.google.gson.Gson;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.Jwts;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.web.filter.GenericFilterBean;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

/**
 * @author /
 */
@Slf4j
public class TokenBuyerFilter extends GenericFilterBean {

    private final TokenUtil tokenUtil;
    private final Cache cache;
    public TokenBuyerFilter(TokenUtil tokenUtil,Cache cache) {
        this.tokenUtil = tokenUtil;
        this.cache = cache;
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
            throws IOException, ServletException {
        HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
        HttpServletResponse httpServletResponse = (HttpServletResponse) servletResponse;
        // 验证 token 是否存在
        String authToken = "";
        try {
            authToken = tokenUtil.getTokenUni(httpServletRequest);
            if (authToken == null) {
                filterChain.doFilter(httpServletRequest, servletResponse);
                return;
            }
        } catch (ExpiredJwtException e) {
            log.error(e.getMessage());
        }
        final UsernamePasswordAuthenticationToken authentication1 = getAuthentication(authToken, httpServletResponse);
        if (ObjectUtil.isNotEmpty(authentication1)) {
            if (cache.hasKey(CachePrefix.ACCESS_TOKEN.getPrefix(UserEnums.MANAGER) + authToken)) {
                SecurityContextHolder.getContext().setAuthentication(authentication1);
            } else {
                SecurityContextHolder.getContext().setAuthentication(authentication1);
            }
        } else {
            //throw new ServiceException(ResultCode.USER_OVERDUE_CONNECT_ERROR);
            return;
        }
        filterChain.doFilter(httpServletRequest, servletResponse);
    }

    /**
     * 解析用户
     *
     * @param jwt
     * @param response
     * @return
     */
    private UsernamePasswordAuthenticationToken getAuthentication(String jwt, HttpServletResponse response) {
        try {
            //获取存储在claims中的用户信息
            final AuthUser authUser = tokenUtil.getAuthUser(jwt);
            //校验redis中是否有权限
            if (cache.hasKey(CachePrefix.ACCESS_TOKEN.getPrefix(UserEnums.MEMBER) + jwt)
                    || cache.hasKey(CachePrefix.ACCESS_TOKEN.getPrefix(UserEnums.MANAGER) + jwt)) {
                //构造返回信息
                UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(authUser.getUsername(), null, null);
                authentication.setDetails(authUser);
                return authentication;
            }
            ResponseUtil.output(response, 403, ResponseUtil.resultMap(false, 403, "登录已失效，请重新登录"));
            return null;
        } catch (ExpiredJwtException e) {
            log.debug("user analysis exception:", e);
        } catch (Exception e) {
            log.error("user analysis exception:", e);
        }
        return null;
    }
}
